import { MongodbClient } from "../lib/db.client.mongodb";
import { PgClient } from "../lib/db.client.pg";

import { ENUM_TON_NOTCH, ENUM_TON_ORDER, OrderStock, TonOrder, TonSku, User } from "qqlx-core";
import { getConditionMatchEnum, toDivideSafe, TonSkuSchema, getConditionMatchStr, getTplIvId, toMultiplySafe, OrderStockSchema, toNumber } from "qqlx-cdk";

import { User as OldUser } from "../../../qqlx.old/qqlx-core";
import { Corp as OldCorp } from "../../../qqlx.old/qqlx-core";
import { Order as OldOrder, ENUM_ORDER } from "../../../qqlx.old/qqlx-core";
import { Sku } from "../../../qqlx.old/qqlx-core";

import { OrderStockDao, TonSkuDao } from "../dao/river";
import { ENUM_POUNDS_FORMULA } from "../../../qqlx.old/qqlx-core";
import { doBashPrint } from "../lib/log";
import { ObjectId } from "mongodb";

export async function doTonSkuGetinInsert(
  mongo_master_corp_id: OldCorp["_id"],
  _id_to_user_map: Map<OldUser["_id"], User>,
  _id_to_buy_order_map: Map<OldUser["_id"], TonOrder>,
  pg_buy_order_uuiid32_to_skus_map: Map<TonOrder["uuid32"], TonSku[]>,
  pg_uuid32_buy_order_map: Map<TonOrder["uuid32"], TonOrder>,
) {
  const mongodbClient = new MongodbClient("mongodb://localhost:27017/qqlx");
  const pgClient = new PgClient("127.0.0.1", "5432", "production", "postgres", "postgres");

  console.group("\n开始迁移mongo商品采购入库数据");
  const stat = { before: 0, wanner: 0, now: 0 };

  try {
    await mongodbClient.start();
    const colCorps = mongodbClient.getCollection("corps");
    const corp = (await colCorps.findOne<OldCorp>({ _id: mongo_master_corp_id as unknown as ObjectId })) as OldCorp;
    const corpQuery = { corpId: corp._id as unknown as ObjectId };

    // 历史采购订单
    const orderQuery = { ...corpQuery, type: ENUM_ORDER.PURCHASE };
    const colOrders = mongodbClient.getCollection("orders");
    const mongo_buy_order_list = await colOrders.find<OldOrder>(orderQuery).toArray();
    console.log("旧数据（采购订单）", mongo_buy_order_list.length);

    /** 历史入库订单 */
    const mongo_getin_order_list = await colOrders
      .find<OldOrder>({
        ...corpQuery,
        type: ENUM_ORDER.GETIN,
        parentOrderId: { $ne: "" },
        parentOrderType: ENUM_ORDER.PURCHASE,
        isDisabled: false,
      })
      .toArray();

    /** 根据入库订单id，查询采购订单id */
    const _oldGetinOrderMap = new Map<string, string>();
    for (const getin of mongo_getin_order_list) {
      if (!getin.parentOrderId) throw { message: `入库订单异常：${getin._id}` };
      const purchaseOrderId = getin.parentOrderId;
      _oldGetinOrderMap.set(getin._id, purchaseOrderId);
    }
    console.log("旧数据（入库订单）", mongo_getin_order_list.length);

    // 历史入库商品
    const colSkus = mongodbClient.getCollection("skus");
    const skuQuery = { orderId: { $in: mongo_getin_order_list.map((d) => d._id) } };
    const oldGetinSkus = await colSkus.find<Sku>({ ...corpQuery, ...skuQuery }).toArray();
    console.log("旧数据（入库商品）", oldGetinSkus.length);
    stat.wanner = oldGetinSkus.length;

    /** 根据采购订单id，查询入库商品 */
    const _id_to_getin_sku_map = new Map<string, Sku[]>();
    for (const getinSku of oldGetinSkus) {
      const purchaseOrderId = _oldGetinOrderMap.get(getinSku.orderId) as string;
      if (!purchaseOrderId) throw { message: `入库>采购订单异常：${getinSku.orderId}` };

      if (!_id_to_getin_sku_map.has(purchaseOrderId)) _id_to_getin_sku_map.set(purchaseOrderId, []);
      _id_to_getin_sku_map.get(purchaseOrderId)!.push(getinSku);
    }

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    const pgClientIns = await pgClient.start();
    const skuDao = new TonSkuDao(pgClientIns.getRepository<TonSku>(TonSkuSchema));
    const orderStockDao = new OrderStockDao(pgClientIns.getRepository<OrderStock>(OrderStockSchema));

    const master = _id_to_user_map.get(corp.userId) as User;
    const condisMaster = [getConditionMatchStr("refOwnerUUid32", master.uuid32), getConditionMatchEnum("type", ENUM_TON_ORDER.PURCHASE_IN)];

    const pgCount = await skuDao.count(condisMaster);
    if (pgCount === 0) {
      const errorCount = { value: 0 };

      //
      const schemaLs: TonSku[] = [];
      mongo_buy_order_list.map((mongo_buy_order) => {
        for (const getinSku of _id_to_getin_sku_map.get(mongo_buy_order._id) || []) {
          const { schema, isError } = getDefaultSku(getinSku);
          if (isError) errorCount.value++;

          const pg_order = _id_to_buy_order_map.get(mongo_buy_order._id) as TonOrder;
          schema.refOwnerUUid32 = pg_order.refOwnerUUid32;

          schema.refTonOrderGroupId = pg_order.refTonOrderGroupId;
          schema.refTonOrderId = pg_order.uuid32;
          schema.isOrderDisabled = pg_order.isDisabled;

          schema.formulaName = getinSku.formula === ENUM_POUNDS_FORMULA.TS_PLATE ? "冷轧板过磅公式" : ""; // 税额如果大于0，表示需要公式
          schema.formulaContent = getinSku.formula === ENUM_POUNDS_FORMULA.TS_PLATE ? "7.85*(A/10)*(B/10)*(C/10)/1000/1000" : "";

          // 交易7要素
          schema.tradeId = "";
          schema.tradeTime = pg_order.tradeTime;
          schema.tradeYear = pg_order.tradeYear;
          schema.tradeMonth = pg_order.tradeMonth;
          schema.tradeScope = pg_order.tradeScope;
          schema.refCreatorId = pg_order.refCreatorId;
          schema.refContactId = pg_order.refContactId;
          schemaLs.push(schema);

          if (!pg_buy_order_uuiid32_to_skus_map.has(pg_order.uuid32)) {
            pg_buy_order_uuiid32_to_skus_map.set(pg_order.uuid32, []);
          }
          pg_buy_order_uuiid32_to_skus_map.get(pg_order.uuid32)!.push(schema);
        }
      });
      console.log("异常商品个数", errorCount);

      // 1.迁移入库/入库商品
      const batchCount = 2000;
      const createds: TonSku[] = [];
      while (schemaLs.length > 0) {
        const part = schemaLs.splice(0, batchCount);
        const ls = await skuDao.insertManyAndQuery(part);
        createds.push(...ls);
        doBashPrint(`正在推送商品（${batchCount}）剩余${schemaLs.length}`);
      }

      // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
      // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
      // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
      // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
      // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
      // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
      // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
      // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
      // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 准备订单库存

      const orderStockCountSchemaLs: OrderStock[] = [];
      const orderStockTonSchemaLs: OrderStock[] = [];
      for (const [orderId, skuLs] of pg_buy_order_uuiid32_to_skus_map) {
        const { count, ton } = getNotchStat(skuLs);
        const pg_order = pg_uuid32_buy_order_map.get(orderId) as TonOrder;
        if (pg_order.isDisabled) continue;

        const countSchema = new OrderStockSchema();
        countSchema.tradeId = pg_order.tradeId;
        countSchema.tradeTime = pg_order.timeCreate;
        countSchema.tradeYear = new Date(toNumber(pg_order.timeCreate)).getFullYear();
        countSchema.tradeMonth = new Date(toNumber(pg_order.timeCreate)).getMonth() + 1;
        countSchema.tradeScope = pg_order.tradeScope;
        countSchema.refCreatorId = pg_order.refCreatorId;
        countSchema.refContactId = pg_order.refContactId; // 交易七要素
        countSchema.refOwnerUUid32 = master.uuid32;
        countSchema.type = ENUM_TON_NOTCH.NOT_IN;
        countSchema.key = "count";
        countSchema.total = count.toString();
        orderStockCountSchemaLs.push(countSchema);

        const tonSchema = new OrderStockSchema();
        tonSchema.tradeId = pg_order.tradeId;
        tonSchema.tradeTime = pg_order.timeCreate;
        tonSchema.tradeYear = new Date(toNumber(pg_order.timeCreate)).getFullYear();
        tonSchema.tradeMonth = new Date(toNumber(pg_order.timeCreate)).getMonth() + 1;
        tonSchema.tradeScope = pg_order.tradeScope;
        tonSchema.refCreatorId = pg_order.refCreatorId;
        tonSchema.refContactId = pg_order.refContactId; // 交易七要素
        tonSchema.refOwnerUUid32 = master.uuid32;
        tonSchema.type = ENUM_TON_NOTCH.NOT_IN;
        tonSchema.key = "ton";
        tonSchema.total = ton.toString();
        orderStockTonSchemaLs.push(tonSchema);
      }

      // 2.推送订单库存
      const batchCount2 = 2000;
      while (orderStockCountSchemaLs.length > 0) {
        const part = orderStockCountSchemaLs.splice(0, batchCount2);
        await orderStockDao.insertMany(part);
        doBashPrint(`正在推送订单库存（${batchCount2}）剩余${orderStockCountSchemaLs.length}`);
      }
      while (orderStockTonSchemaLs.length > 0) {
        const part = orderStockTonSchemaLs.splice(0, batchCount2);
        await orderStockDao.insertMany(part);
        doBashPrint(`正在推送订单库存（${batchCount2}）剩余${orderStockTonSchemaLs.length}`);
      }
    }

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    const pgCountFinal = await skuDao.count(condisMaster);
    stat.now = pgCountFinal;

    console.log(`🔴迁移前 >> 迁移后 / river_ton_sku_sale`, stat.before, stat.now);
    console.log(`期望`, stat.wanner);
    console.log(`📉误差`, stat.now - stat.before - stat.wanner);
    console.groupEnd();
    console.log("====================================");
  } finally {
    await pgClient.stop();
    await mongodbClient.stop();
  }
}

function getDefaultSku(mongo_sku: Sku) {
  const schema: TonSku = new TonSkuSchema();
  schema.timeCreate = mongo_sku.timeCreate.toString();
  schema.timeUpdate = mongo_sku.timeUpdate.toString();
  schema.type = ENUM_TON_ORDER.PURCHASE_IN;

  schema.count = Math.abs(mongo_sku.count);
  schema.ton = Math.abs(mongo_sku.isPriceInPounds ? toDivideSafe(mongo_sku.pounds, 1000, 3) : 0);
  schema.isTonAble = mongo_sku.isPriceInPounds;
  schema.price = 0;

  schema.name = mongo_sku.name || "-";
  schema.norm = mongo_sku.norm || "-";
  schema.unit = mongo_sku.unit || "-";
  schema.remark = mongo_sku.remark;
  schema.ivid = getTplIvId(schema, "");

  const isError = [schema.name, schema.norm, schema.unit].includes("-");
  return { schema, isError };
}

function getNotchStat(skuLs: TonSku[]) {
  const result = { count: 0, ton: 0 };
  const positive = [ENUM_TON_ORDER.PURCHASE, ENUM_TON_ORDER.SALE_RETURN];
  const negative = [ENUM_TON_ORDER.PURCHASE_IN, ENUM_TON_ORDER.SALE_RETURN_IN];
  const POSITIVE = skuLs
    .filter((sku) => positive.includes(sku.type))
    .reduce(
      (acc, sku) => {
        acc.count += toMultiplySafe(sku.count, 1000);
        acc.ton += toMultiplySafe(sku.ton, 1000);
        return acc;
      },
      { count: 0, ton: 0 },
    );
  const NEGATIVE = skuLs
    .filter((sku) => negative.includes(sku.type))
    .reduce(
      (acc, sku) => {
        acc.count += toMultiplySafe(sku.count, 1000);
        acc.ton += toMultiplySafe(sku.ton, 1000);
        return acc;
      },
      { count: 0, ton: 0 },
    );

  result.count = toDivideSafe(POSITIVE.count - NEGATIVE.count, 1000, 3);
  result.ton = toDivideSafe(POSITIVE.ton - NEGATIVE.ton, 1000, 3);
  return result;
}
